package com.zmx.user.service;

import com.zmx.common.common.contents.cache.UserCacheContents;
import com.zmx.common.common.exception.BusinessException;
import com.zmx.common.common.invocation.InvocationInfoProxy;
import com.zmx.common.common.security.dto.OauthTokenDto;
import com.zmx.common.common.utils.HttpUtil;
import com.zmx.common.common.utils.JacksonUtil;
import com.zmx.common.common.utils.Utils;
import com.zmx.common.common.web.rest.ResponseResult;
import com.zmx.user.dto.LoginParameterDto;
import com.zmx.user.dto.SysUserDto;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.shaded.com.google.common.base.Preconditions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Description:
 * @ClassName: OldLoginService
 * @Author zhaomxr
 * @Date 2022-01-07 10:12
 */
@Slf4j
@Service
public class SysLoginService {

    @Value("${security.oauth2.client.access-token-uri}")
    private String accessTokenUrl;
    @Value("${security.oauth2.client.client-id}")
    private String clientId;
    @Value("${security.oauth2.client.client-secret}")
    private String secret;

    @Autowired
    private UserService userService;
    @Autowired
    private RedisTemplate redisTemplate;


    public ResponseResult<Map> login(LoginParameterDto loginParameterDto, HttpServletRequest request) {
        //查询用户是否存在
        SysUserDto user = userService.getUserByUserName(loginParameterDto.getUsername());

        //登录前校验
        checkUsernameAndPassword(loginParameterDto, user, request);

        //获取tocken
        OauthTokenDto oauthTokenDto = getToken(loginParameterDto);
        String token = oauthTokenDto.getAccess_token();
        if (oauthTokenDto == null || StringUtils.isEmpty(token)) {
            throw new BusinessException("登录认证失败！");
        }

        //当前token值及其他数据放入InvocationInfoProxy中
        InvocationInfoProxy.setUserId(String.valueOf(user.getId()));
        InvocationInfoProxy.setUserName(user.getUserName());
        InvocationInfoProxy.setTocken(token);
        InvocationInfoProxy.setOauthTokenDto(oauthTokenDto);
        redisTemplate.opsForValue().set(UserCacheContents.PREFIX_TOKEN + InvocationInfoProxy.getUserId(), token, 30, TimeUnit.DAYS);
        Map<String, String> data = new HashMap<String, String>(1);
        data.put("token", token);
        data.put("userId", String.valueOf(user.getId()));
        data.put("userName", user.getUserName());
        StringBuilder cookie = new StringBuilder();
        data.forEach((key, value) -> {
            cookie.append(key);
            cookie.append("=");
            cookie.append(value);
            cookie.append("; ");
        });
        String reverseCookie = cookie.reverse().toString().replaceFirst("; ", "");
        data.put("Cookie", new StringBuilder(reverseCookie).reverse().toString());
        log.info("登录成功 user:{}", data.toString());

        return ResponseResult.success("登录成功", data);
    }

    /**
     * 登出
     */
    public void loginOut() {
        String userId = InvocationInfoProxy.getUserId();
        String userName = InvocationInfoProxy.getUserName();
        log.info("用户id：{}, 用户名称：{} 退出登录", userId, userName);
        redisTemplate.delete(UserCacheContents.PREFIX_TOKEN + userId);
        InvocationInfoProxy.clear();
    }

    private void checkUsernameAndPassword(LoginParameterDto loginParameterDto, SysUserDto user, HttpServletRequest request) {
        Preconditions.checkNotNull(loginParameterDto, "请求参数不能为空！");
        Preconditions.checkArgument(!StringUtils.isEmpty(loginParameterDto.getUsername()), "用户名不能为空！");
        Preconditions.checkArgument(!StringUtils.isEmpty(loginParameterDto.getPassword()), "密码不能为空！");
        //Preconditions.checkArgument(!StringUtils.isEmpty(loginParameterDto.getVerifyCode()), "验证码不能为空！");

        if (user == null) {
            throw new UsernameNotFoundException("用户名或密码错误！");
        }
        //Object checkedCode = request.getSession().getAttribute("verifyCode");
        //if (checkedCode == null || !Objects.equals(checkedCode, loginParameterDto.getVerifyCode())) {
        //    throw new UsernameNotFoundException("验证码错误！");
        //}

        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(6);
        boolean isPassword = passwordEncoder.matches(loginParameterDto.getPassword(), user.getPassWord());
        if (!isPassword) {
            throw new UsernameNotFoundException("用户名或密码错误！");
        }
    }

    private OauthTokenDto getToken(LoginParameterDto loginParameterDto) {
        OauthTokenDto oauthTokenDto = new OauthTokenDto();

        //构建请求参数
        Map<String, Object> params = new HashMap<String, Object>(4);
        params.put("grant_type", "password");
        params.put("username", loginParameterDto.getUsername());
        params.put("password", loginParameterDto.getPassword());
        params.put("scope", "all");

        //构建请求头
        Map<String, String> headers = new HashMap<String, String>(3);
        headers.put("Accept", "*/*");
        headers.put("Cache-Control", "no-cache");
        headers.put("Authorization", "Basic " + Utils.base64EnCode(clientId + ":" + secret));

        StringBuilder url = new StringBuilder();
        url.append(accessTokenUrl);
        url.append("?");
        params.forEach((key, value) -> {
            url.append(key);
            url.append("=");
            url.append(value);
            url.append("&");
        });
        log.info("get token url is: {}", url.toString());

        try {
            String result = HttpUtil.post(url.toString(), null, headers);
            if (!StringUtils.isEmpty(result)) {
                oauthTokenDto = JacksonUtil.jsonStringToBean(result, OauthTokenDto.class);
            }
        } catch (Exception e) {
            throw new BusinessException(e.getMessage(), e);
        }

        return oauthTokenDto;
    }
}
